/** @file         rb_tree_api_for_cm
 *  @brief        cm 的底层数据结构
 *  @details      提供对cm的CURD操作，底层是通过红黑树实现的
 *  @author       Schips
 *  @date         2020/10/25
 *  @version      v1.0
 *  @copyright    Copyright By Schips, All Rights Reserved
 *
 ***********************************************************************************
 *
 *  @par 修改日志:
 *  <table>
 *  <tr><th>Date        <th>Version  <th>Author    <th>Description
 *  <tr><td>2020/10/25  <td>1.0      <td>Schips	   <td>创建初始版本
 *  </table>
 *
 **********************************************************************************
 */
#include <linux/types.h>  
#include <linux/errno.h>
#include <linux/cdev.h>

typedef  unsigned char * key;
typedef  struct cdev_st  val;

struct cdev_st {
	unsigned char*    cdev_name;
	/** 字符设备框架 **/
    dev_t              devid;             //设备号
    struct cdev        cdev;              //字符设备
    struct class       *class;            //类
    struct device      *device;           //设备
    struct file_operations* fops;
};

struct cdev_info {
    int ready_flag;     // 是否初始化就绪
    int count;
};

struct user_data {
    //为了方便管理的
    struct cdev_info cdev_info; 
    // 内核有关的
	struct cdev_st   cdev_st;
};
 
struct user_rb_t {
	struct rb_node rbnode;
    struct user_data data;
};
#define cdev_data user_data 
#include "rbtree_augmented.h"

#define FOR_KERNEL_SPACE
#include "rb_tree_port.h"
#include "cdev_manager.h"
 
#include <linux/string.h>

/******************* 内部函数 *******************/
int  _linux_create_cdev(struct user_rb_t * node);
void _linux_remove_cdev(struct user_rb_t * node);
 
/******************* 全局变量 *******************/
static struct rb_root root = RB_ROOT;

/******************* 底层接口 *******************/
static void print_node(const char *event, struct user_rb_t *target);

void assign_val(val *var, val val)
{
    if(!var) return;
    //*var = val;
	memcpy(var, &val, sizeof(struct cdev_st));
}

void assign_key(key var, key key)
{
    var = key;
}

int key_compare(key a1, key a2)
{
    int ret;
	//ret = memcmp(a1, a2, BUFFER_SIZE);
	ret = strcmp(a1, a2);
    return ret;
}

//  创建节点
struct user_rb_t * create_user_node(void)
{
	struct user_rb_t *node;
	
    PRINT(PRINT_LV "create_user_node\n");
	node = (struct user_rb_t *)MALLOC(sizeof(struct user_rb_t));
	if (NULL == node)
		return NULL;
	memset(node, 0, sizeof(struct user_rb_t));

    //assign_key((node->data.cdev_st.cdev_name), key);
    //assign_val(&(node->data.val), val);
	return node;
}
 
// 查找节点（根据key）
struct user_rb_t * user_node_find(struct rb_root *root, key key)//, val val)
{
	struct rb_node *node = root->rb_node;
	struct user_rb_t * target = NULL;
	int ret = 0;
    PRINT(PRINT_LV "user_node_find\n");
 
	while (node) {
		target = rb_entry(node, struct user_rb_t, rbnode);

        ret = key_compare(target->data.cdev_st.cdev_name, key);

		if (ret < 0) {
			node = node->rb_left;
		} else if (ret > 0) {
			node = node->rb_right;
		} else
			return target;
	}
    PRINT(PRINT_LV "user_node_find not found\n");
	return NULL;
}
 
// 删除单个节点
void user_rb_delete(struct rb_root *root, key key)
{
	struct user_rb_t *target = user_node_find(root, key);
	if (NULL != target) {
		rb_erase(&target->rbnode, root);
        print_node("user_rb_delete", target);
		FREE(target);
	}
}

// 删除整棵红黑树
void user_rb_destroy(struct rb_root *root)
{
	struct rb_node *node = NULL, *tmp_node = NULL;
	struct user_rb_t * target = NULL;
 
    // 安全遍历
	for (node = rb_first(root); node;) {
		tmp_node = rb_next(node);
		target = rb_entry(node, struct user_rb_t, rbnode);
		rb_erase(node, root);
		FREE(target);
		node = tmp_node;
	}
}

void cm_destroy(void)
{
	struct rb_node *node = NULL, *tmp_node = NULL;
	struct user_rb_t * target = NULL;
 
    // 安全遍历
	for (node = rb_first(&root); node;) {
		tmp_node = rb_next(node);
		target = rb_entry(node, struct user_rb_t, rbnode);

        if(target->data.cdev_info.ready_flag == READY_FLAG_INITED)
        {
            _linux_remove_cdev(target);
        }

		rb_erase(node, &root);
		FREE(target);
		node = tmp_node;
	}
}

static void print_node(const char *event, struct user_rb_t *target)
{
    if(!target) return ;
    PRINT("--%15s\t[%p] name: [%s], count: [%d]\n",
            event,
            target,
            target->data.cdev_st.cdev_name,
            target->data.cdev_info.count);
}
 
// 遍历红黑树(从小到大)
static void tranverse(struct rb_root *root)
{
	struct rb_node *node;
    struct user_rb_t *target;
    PRINT("tranverse\n");
	for (node = rb_first(root); node; node = rb_next(node)) {
		target = rb_entry(node, struct user_rb_t, rbnode);
        print_node("tranverse", target);
	}
}

int _linux_create_cdev(struct user_rb_t * node)
{
    int ret = 0;
    struct cdev_st*   p_cdev_node = &(node->data.cdev_st);
    struct cdev_info* p_cdev_info = &(node->data.cdev_info);
    if(!node) return -1;
/** 字符设备框架 **/    
    /* 注册设备号 */
    ret = alloc_chrdev_region(&(p_cdev_node->devid), 
                              0, // 0代表自动创建 
                              p_cdev_info->count, 
                              p_cdev_node->cdev_name);
    if(ret < 0) {
        PRINT(PRINT_LV "can not get device number\n");
        goto chrdev_region_error;
    }
    
    /* 初始化字符设备结构体 */
    cdev_init(&(p_cdev_node->cdev), p_cdev_node->fops);
    
    /* 注册字符设备 */
    ret = cdev_add(&(p_cdev_node->cdev),
                   p_cdev_node->devid,
                   p_cdev_info->count);
    if(ret < 0)
    {
        PRINT(PRINT_LV "cdev_add falied\n");
        goto cdev_add_error;
    }
    
    /* 创建类 */
    p_cdev_node->class = class_create(THIS_MODULE, p_cdev_node->cdev_name);
    if(IS_ERR(p_cdev_node->class)) 
    {
        PRINT(PRINT_LV "class_create error\n");
        ret = PTR_ERR(p_cdev_node->class);
        goto class_create_error;
    }
    
    /* 创建设备节点 */
    p_cdev_node->device = device_create(p_cdev_node->class, NULL, 
                                     p_cdev_node->devid, NULL, 
                                     p_cdev_node->cdev_name);
    if (IS_ERR(p_cdev_node->device)) 
    {
        PRINT(PRINT_LV "device_create error\n");
        ret = PTR_ERR(p_cdev_node->device);
        goto device_create_error;
    }
    p_cdev_info->ready_flag = READY_FLAG_INITED;

    PRINT(PRINT_LV "[%s] inited.\n", p_cdev_node->cdev_name);
    return 0;  

/* 出错判断 */
device_create_error :
    class_destroy(p_cdev_node->class);
    p_cdev_node->class = NULL;
class_create_error :
    cdev_del(&p_cdev_node->cdev);
cdev_add_error :
    unregister_chrdev_region(p_cdev_node->devid,
                             p_cdev_info->count);
chrdev_region_error :
    return ret;
}

void _linux_remove_cdev(struct user_rb_t * node)
{
    struct cdev_st*   p_cdev_node = &(node->data.cdev_st);
    struct cdev_info* p_cdev_info = &(node->data.cdev_info);
    if(!node) return ;

/** 字符设备框架 **/
    /* 注销字符设备 */
    cdev_del(&p_cdev_node->cdev);
    
    /* 注销设备号 */
    unregister_chrdev_region(p_cdev_node->devid, 
                             p_cdev_info->count);
    
    /* 删除设备节点 */
    device_destroy(p_cdev_node->class, p_cdev_node->devid);
    
    /* 删除类 */
    class_destroy(p_cdev_node->class);
    
    PRINT(PRINT_LV "[%s] deinited.\n", p_cdev_node->cdev_name);
}

// 插入一个新设备
int cm_add_cdev(char *cdev_name, unsigned int count, struct file_operations* cdev_fops)
{
	struct rb_node **new = &(root.rb_node);
	struct rb_node *parent = NULL;
	struct user_rb_t *target = NULL;
	int res = 0;

    if(!cdev_fops) return -1;
	while (*new) {
		parent = *new;
		target = rb_entry(*new, struct user_rb_t, rbnode);
        res = key_compare(target->data.cdev_st.cdev_name, cdev_name);
        
		if (res < 0) {
			new = &((*new)->rb_left);
		} else if (res > 0) {
			new = &((*new)->rb_right);
		} else
        {
            // 存在相同的结点，需要判断
            if(target->data.cdev_info.ready_flag == READY_FLAG_INITED)
            {
                PRINT(PRINT_LV "READY_FLAG_INITED\n");
                return 0;
            }
        }
	}
	target = create_user_node();
	if (NULL == target)
		return -1;
	// add new node
	rb_link_node(&target->rbnode, parent, new);
	// rebalance rbtree
	rb_insert_color(&target->rbnode, &root);

    PRINT(PRINT_LV "Try init\n");
    // 以下是初始化操作
    target->data.cdev_st.cdev.owner = THIS_MODULE;
    target->data.cdev_st.fops = cdev_fops;
    target->data.cdev_info.count = count;
    target->data.cdev_st.cdev_name = cdev_name;
    print_node("Insert node", target);

    res = _linux_create_cdev(target);
    if(res) // 创建失败，删除结点
    {
        user_rb_delete(&root, cdev_name);
    }

    return res;
}

void cm_remove_cdev(char *cdev_name)
{
	struct user_rb_t *target = user_node_find(&root, cdev_name);
	if (NULL != target) 
    {
        if(target->data.cdev_info.ready_flag == READY_FLAG_INITED)
        {
            _linux_remove_cdev(target);
        }
        print_node("user_rb_delete", target);
		rb_erase(&target->rbnode, &root);
		FREE(target);
	}
}

void cm_dump(void) 
{
    tranverse(&root);
    return;
}
